﻿// ==========================================================================
//  Squidex Headless CMS
// ==========================================================================
//  Copyright (c) Squidex UG (haftungsbeschraenkt)
//  All rights reserved. Licensed under the MIT license.
// ==========================================================================

using System.Globalization;
using System.Text;
using System.Text.Json;

namespace GenerateLanguages;

public static class Program
{
    public static void Main()
    {
        var languageCodesFile = new FileInfo("../../../../../src/Squidex.Infrastructure/Languages.cs");

        var languages = ReadLanguages();

        var writer = new SourceBuilder();
        writer.WriteLine("// ==========================================================================");
        writer.WriteLine("//  Languages.cs");
        writer.WriteLine("//  Squidex Headless CMS");
        writer.WriteLine("// ==========================================================================");
        writer.WriteLine("//  Copyright (c) Squidex UG (haftungsbeschränkt)");
        writer.WriteLine("//  All rights reserved. Licensed under the MIT license.");
        writer.WriteLine("// ==========================================================================");
        writer.WriteLine("// <autogenerated/>");
        writer.WriteLine();
        writer.WriteLine("using System.CodeDom.Compiler;");
        writer.WriteLine();
        writer.WriteLine("namespace Squidex.Infrastructure");
        writer.WriteLine("{");
        writer.WriteLine("[GeneratedCode(\"LanguagesGenerator\", \"1.0\")]");
        writer.WriteLine("public partial record Language");
        writer.WriteLine("{");
        writer.WriteLine("private static readonly Dictionary<string, Language> LanguageByCode = new Dictionary<string, Language>(StringComparer.OrdinalIgnoreCase);");
        writer.WriteLine("private static readonly Dictionary<string, string> NamesEnglish = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);");
        writer.WriteLine("private static readonly Dictionary<string, string> NamesNative = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);");
        writer.WriteLine();
        writer.WriteLine("internal static Language AddLanguage(string iso2Code, string englishName, string nativeName)");
        writer.WriteLine("{");
        writer.WriteLine("NamesEnglish[iso2Code] = englishName;");
        writer.WriteLine("NamesNative[iso2Code] = nativeName;");
        writer.WriteLine();
        writer.WriteLine("return LanguageByCode.GetOrAdd(iso2Code, code => new Language(code));");
        writer.WriteLine("}");
        writer.WriteLine();

        foreach (var language in languages)
        {
            writer.WriteLine($"public static readonly Language {language.FieldName} = AddLanguage(\"{language.Code}\", \"{language.NameEnglish}\", \"{language.NameNative}\");");
        }

        writer.WriteLine("}");
        writer.WriteLine("}");

        File.WriteAllText(languageCodesFile.FullName, writer.ToString());
    }

    private static List<Language> ReadLanguages()
    {
        var languages = new List<Language>();

        var json = File.ReadAllText("languages.json");

        var deserialized = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(json);

        static string ToFieldName(string name)
        {
            var sb = new StringBuilder();

            foreach (var c in name)
            {
                if (char.IsLetterOrDigit(c))
                {
                    sb.Append(c);
                }
            }

            return sb.ToString();
        }

        foreach (var (code, value) in deserialized)
        {
            var name = value["name"];

            languages.Add(new Language
            {
                Code = code,
                NameNative = value["nativeName"],
                NameEnglish = value["name"],
                FieldName = code.ToUpperInvariant()
            });
        }

        foreach (var culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
        {
            var code = culture.ToString();

            if (code.Length == 5 && languages.Any(l => l.Code.Equals(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase)))
            {
                languages.Add(new Language
                {
                    Code = code,
                    NameNative = culture.NativeName,
                    NameEnglish = culture.EnglishName,
                    FieldName = ToFieldName(culture.EnglishName)
                });
            }
        }

        var oldFile = File.ReadAllLines("old-languages.csv");

        foreach (var line in oldFile.Skip(1))
        {
            var code = line.Substring(1, 2);

            if (!languages.Any(x => x.Code == code))
            {
                throw new InvalidOperationException($"Cannot find old language code {code}.");
            }
        }

        return languages;
    }
}
